#ifndef _OH_BASE_H
#define _OH_BASE_H

#ifdef __cplusplus
    #define _OH_BEGIN namespace oh{
    #define _OH_END   }

    #define _OH_POLICY_BEGIN namespace policy{
    #define _OH_POLICY_END   }

	#define _OH_SCENE_BEGIN namespace scene{
	#define _OH_SCENE_END   }

	#define _OH_MATH_BEGIN	namespace math{
	#define _OH_MATH_END	}

	#define _OH_MATH_GEOMETRY_BEGIN	namespace geometry{
	#define _OH_MATH_GEOMETRY_END	}
#else
    #define _OH_BEGIN
    #define _OH_END

    #define _OH_POLICY_BEGIN
    #define _OH_POLICY_END

	#define _OH_SCENE_BEGIN
	#define _OH_SCENE_END

	#define _OH_MATH_BEGIN
	#define _OH_MATH_END

	#define _OH_MATH_GEOMETRY_BEGIN
	#define _OH_MATH_GEOMETRY_END
#endif // __cplusplus

#ifndef NULL
    #define NULL (0)
#endif // NULL

_OH_BEGIN

// Basic typedefs
#ifdef _MSC_VER
	typedef int			Int;
	typedef __int8		Int8;
	typedef __int16		Int16;
	typedef __int32		Int32;
	typedef __int64		Int64;

	typedef unsigned int		UInt;
	typedef unsigned __int8		UInt8;
	typedef unsigned __int16	UInt16;
	typedef unsigned __int32	UInt32;
	typedef unsigned __int64	UInt64;

	typedef signed int		SInt;
	typedef signed __int8	SInt8;
	typedef signed __int16	SInt16;
	typedef signed __int32	SInt32;
	typedef signed __int64	SInt64;

	typedef float	Float;
	typedef float	Float32;
	typedef double	Float64;
	
	typedef char			Char;
	typedef signed char		SChar;
	typedef unsigned char	UChar;

	typedef bool	Bool;
#endif // _MSC_VER

// ----- Conversion Test ---------------------------
template <class From, class To>
class ConversionTest
{
    typedef char Small;
    class Big
    {
        char dummy[2];
    };
    static Small Test(To const& );
    static Big   Test(...);
    static From MakeFrom();
public:
    enum { exists = sizeof(Test(MakeFrom())) == sizeof(Small) };
    enum { same = false };
};

template <class T>
class ConversionTest<T, T>
{
public:
    enum { exists = true };
    enum { same   = true };
};

// ----- Converts Test ---------------------------
// TODO: test using this
#define CONVERTS(U, T)                                                  \
    (ConversionTest<U, T>::exists)

#define CONVERTS_STRICT(U, T)                                           \
    (ConversionTest<U, T>::exists && !ConversionTest<U, T>::same )

// ----- Inherits Test ---------------------------
#define INHERITS(U, T)                                                  \
    (ConversionTest<U const * const, T const * const>::exists &&        \
    !ConversionTest<T const * const, void const * const>::same)

#define INHERITS_STRICT(U, T)                                           \
    (INHERITS(T, U) &&                                             \
    !ConversionTest<T const * const, U const * const>::same)

// ----- Compile Time Test ---------------------------
template<bool>
struct CompileTimeChecker; 
template<> struct CompileTimeChecker<true> {};
#define STATIC_CHECK(expr, msg)                                         \
{                                                                       \
    CompileTimeChecker<((expr) != 0)>   ERROR_##msg;                    \
    (void)ERROR_##msg;                                                  \
}

// ----- max function ---------------------------
template<typename T>
inline T const& max(T const& a_1, T const& a_2)
{
	return (a_1 > a_2 ? a_1 : a_2);
}

// ----- min function ---------------------------
template<typename T>
inline T const& min(T const& a_1, T const& a_2)
{
	return (a_1 < a_2 ? a_1 : a_2);
}

// ----- SelectTypeIf template ---------------------------
template <bool flag, typename T, typename U>
struct SelectTypeIf;

template <typename T, typename U>
struct SelectTypeIf<true, T, U>
{
	typedef T Result;
};

template <typename T, typename U>
struct SelectTypeIf<false, T, U>
{
	typedef U Result;
};

// ----- SentinelType template ---------------------------
class SentinelType
{
	SentinelType();
	SentinelType(SentinelType const& );
	~SentinelType();
	SentinelType & operator= (SentinelType const& );
};

// ----- Some Exceptions ---------------------------------
class Exception{};
class ENotValid : Exception{};

// ----- Swap function -----------------------------------
template<typename T>
void swap(T & a_t1, T& a_t2)
{
	T const tmp(a_t1);
	a_t1 = a_t2;
	a_t2 = a_t1;
}

_OH_END

#endif // _OH_BASE_H